package com.zzyl.nursing.service.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.date.DatePattern;
import cn.hutool.core.date.LocalDateTimeUtil;
import cn.hutool.core.util.RandomUtil;
import cn.hutool.json.JSONUtil;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.huaweicloud.sdk.iotda.v5.IoTDAClient;
import com.huaweicloud.sdk.iotda.v5.model.*;
import com.zzyl.common.constant.Constants;
import com.zzyl.common.exception.base.BaseException;
import com.zzyl.common.utils.StringUtils;
import com.zzyl.nursing.domain.Device;
import com.zzyl.nursing.dto.DeviceDto;
import com.zzyl.nursing.mapper.DeviceMapper;
import com.zzyl.nursing.service.IDeviceService;
import com.zzyl.nursing.vo.DeviceDetailVo;
import com.zzyl.nursing.vo.DeviceReportDataVo;
import com.zzyl.nursing.vo.ProductVo;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;

import java.time.LocalDateTime;
import java.time.ZoneId;
import java.time.ZoneOffset;
import java.util.*;

/**
 * 设备管理Service业务层处理
 * 
 * @author zhq
 * @date 2025-08-21
 */
@Service
public class DeviceServiceImpl extends ServiceImpl<DeviceMapper, Device> implements IDeviceService
{
    @Autowired
    private DeviceMapper deviceMapper;

    @Autowired
    private IoTDAClient client;
    @Autowired
    private RedisTemplate redisTemplate;

    @Override
    public List<ServiceCapability> queryProduct(String productKey) {
        ShowProductResponse response = client.showProduct(new ShowProductRequest().withProductId(productKey));
        if (response.getHttpStatusCode()!=200){
            throw new BaseException("从IOT平台获取产品详情失败");
        }return response.getServiceCapabilities();
    }

    @Override
    public List<DeviceReportDataVo> queryServiceProperties(String iotId) {
        ArrayList<DeviceReportDataVo> voList = new ArrayList<>();
        try {
            ShowDeviceShadowRequest request = new ShowDeviceShadowRequest();
            request.withDeviceId(iotId);
            ShowDeviceShadowResponse response = client.showDeviceShadow(request);
            if(response.getHttpStatusCode()!=200){
                throw new BaseException("从IOT平台获取设备详情失败");
            }
            List<DeviceShadowData> list = response.getShadow();
            if(CollUtil.isEmpty(list)){
                return voList;
            }
            list.forEach(item->{
                String eventTimeStr = item.getReported().getEventTime();
                Map<String,Object> map = (Map<String, Object>) item.getReported().getProperties();
                map.forEach((k,v)->{
                    LocalDateTime eventTime=null;
                    if(StringUtils.isNotBlank(eventTimeStr)){
                        LocalDateTimeUtil.parse(eventTimeStr, Constants.LOCAL_DATE_FORMATTER)
                                .atZone(ZoneId.from(ZoneOffset.UTC))
                                .withZoneSameInstant(ZoneId.systemDefault())
                                .toLocalDateTime();
                    }
                        DeviceReportDataVo vo = DeviceReportDataVo.builder()
                                .functionId(k)
                                .eventTime(eventTime)
                                .value(v)
                                .build();
                    voList.add(vo);
                });

            });
        }catch (Exception e) {
            throw new BaseException("查询设备上报数据失败");
        }

        return voList;
    }

    /**
     * 查询设备管理
     * 
     * @param id 设备管理主键
     * @return 设备管理
     */
    @Override
    public Device selectDeviceById(Long id)
    {
        return deviceMapper.selectById(id);
    }

    /**
     * 查询设备管理列表
     * 
     * @param device 设备管理
     * @return 设备管理
     */
    @Override
    public List<Device> selectDeviceList(Device device)
    {
        return deviceMapper.selectDeviceList(device);
    }

    /**
     * 新增设备管理
     * 
     * @param device 设备管理
     * @return 结果
     */
    @Override
    public int insertDevice(Device device)
    {
        return deviceMapper.insert(device);
    }

    /**
     * 修改设备管理
     * 
     * @param device 设备管理
     * @return 结果
     */
    @Override
    public int updateDevice(Device device)
    {
        return deviceMapper.updateById(device);
    }

    /**
     * 批量删除设备管理
     * 
     * @param ids 需要删除的设备管理主键
     * @return 结果
     */
    @Override
    public int deleteDeviceByIds(Long[] ids)
    {
        return deviceMapper.deleteBatchIds(Arrays.asList(ids));
    }

    /**
     * 删除设备管理信息
     * 
     * @param id 设备管理主键
     * @return 结果
     */
    @Override
    public int deleteDeviceById(Long id)
    {
        return deviceMapper.deleteById(id);
    }

    @Override
    public void syncProductList() {
        //1.调用IoT平台的api获取产品列表
        ListProductsRequest request=new ListProductsRequest();
        ListProductsResponse listProductsResponse = client.listProducts(request);
        if (listProductsResponse.getHttpStatusCode()!=200){
            throw new BaseException("从IOT平台获取产品列表失败");
        }
        List<ProductSummary> products = listProductsResponse.getProducts();
        //2.存入缓存
        redisTemplate.opsForValue().set(Constants.CACHE_IoT_ALL_PRODUCT, JSONUtil.toJsonStr(products));
    }

    @Override
    public List<ProductVo> allProduct() {
        //1.从缓存中获取
        String restr = (String) redisTemplate.opsForValue().get(Constants.CACHE_IoT_ALL_PRODUCT);
        if (restr==null){
            return List.of();
        }
        //2.封装vo
        return JSONUtil.toList(restr, ProductVo.class);

    }

    @Override
    public void registerDevice(DeviceDto deviceDto) {
        //1.判断设备名称是否重复
        isExitDevcieName(deviceDto.getDeviceName());
        //2.判断设备标记号是否重复
        isExistNodeId(deviceDto.getNodeId());
        //3.判断同一个位置是否绑定过相同产品
        if(Objects.isNull(deviceDto.getPhysicalLocationType())){
            deviceDto.setPhysicalLocationType(-1);
        }
        //4.保存设备到IOT
        AddDeviceResponse response=saveDeviceToIot(deviceDto);
        //5保存设备到数据库
        saveDevice(deviceDto,response.getDeviceId(),response.getAuthInfo().getSecret());
    }

    @Override
    public DeviceDetailVo queryDeviceByDetail(String iotId) {
        //1.从iot平台查询
        ShowDeviceRequest request = new ShowDeviceRequest();
        request.withDeviceId(iotId);
        ShowDeviceResponse response = client.showDevice(request);
        if(response.getHttpStatusCode()!=200){
            throw new BaseException("从iot平台获取数据失败");
        }
        String status = response.getStatus();
        String activeTimeStr = response.getActiveTime();
        Device device = this.lambdaQuery()
                .eq(Device::getIotId, iotId)
                .one();
        if(Objects.isNull(device)){
            throw new BaseException("设备不存在");
        }
        DeviceDetailVo deviceVo = BeanUtil.toBean(device, DeviceDetailVo.class);
        deviceVo.setDeviceStatus(status);
        if (!Objects.isNull(activeTimeStr)) {
            LocalDateTime activeTime = LocalDateTimeUtil.parse(activeTimeStr, DatePattern.UTC_MS_PATTERN);
            //日期时区转换
            activeTime = activeTime.atZone(ZoneId.from(ZoneOffset.UTC))
                    .withZoneSameInstant(ZoneId.of("Asia/Shanghai"))
                    .toLocalDateTime();
            deviceVo.setActiveTime(activeTime);
        }
        return deviceVo;
    }

    private void saveDevice(DeviceDto deviceDto, String deviceId, String secret) {
        Device device= BeanUtil.toBean(deviceDto,Device.class);
        device.setIotId(deviceId);
        device.setSecret(secret);
        if(deviceDto.getPhysicalLocationType().equals(-1)){
            device.setHaveEntranceGuard(0);
        }else{
            device.setHaveEntranceGuard(1);
        }
        try {
            save(device);
        }catch (Exception e){
            throw new BaseException("保存设备到数据库失败了");
        }
    }

    private AddDeviceResponse saveDeviceToIot(DeviceDto deviceDto) {
        AddDeviceRequest request=new AddDeviceRequest();
        AddDevice addDevice=new AddDevice();
        AuthInfo authInfo=new AuthInfo();
        authInfo.withAuthType("SECRET")
                .withSecret(RandomUtil.randomString(32))
                .withSecureAccess(true);
        addDevice.withAuthInfo(authInfo)
                .withNodeId(deviceDto.getNodeId())
                .withProductId(deviceDto.getProductKey())
                .withDeviceName(deviceDto.getDeviceName())
                .withDescription(deviceDto.getDeviceDescription());
        request.withBody(addDevice);
        AddDeviceResponse response = client.addDevice(request);
        if (response.getHttpStatusCode()!=201){
            throw new BaseException("注册设备失败");
        }
        return response;
    }

    private void isExistNodeId(String nodeId) {
        Long count = this.lambdaQuery()
                .eq(Device::getNodeId,nodeId)
                .count();
        if (count>0){
            throw new BaseException("设备标记号重复");
        }
    }

    private void isExitDevcieName(String deviceName) {

        Long count = this.lambdaQuery()
                .eq(Device::getDeviceName, deviceName)
                .count();
        if (count>0){
            throw new BaseException("设备名称重复");
        }
    }
}
